home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d1
/
interce.arc
/
INTERCEP.C
next >
Wrap
C/C++ Source or Header
|
1989-04-18
|
11KB
|
419 lines
/* intercept.c -- spawn a process and intercept BIOS and DOS
* SWI (software interrupt) calls, recording register data to
* a file.
* Demonstrates chaining interrupt handlers.
*************************************************************
* Solely for compilation under Borland's Turbo C.
*************************************************************
* Written 7/31/1987 by:
* Ned Konz
* 210 Oleeta St.
* Ormond Bch, FL 32074 (904)672-2431
* BIX:nkonz CIS:76046,223
*
* Released into the public domain by the author.
*
* Modified 4/11/1989 by:
* Russell Nelson
* 11 Grant St.
* Potsdam, NY 13676 (215)265-5655
* CIS: 70441,205 GEnie: BH01 Internet: nelson@clutx.clarkson.edu
* BITNET: nelson@clutx UUCP: uunet!clutx.clarkson.edu!nelson
*
* No copyright is claimed by Russell Nelson
*
**************************************************************/
/*************************************************************
* This program was written so I could find out quickly what
* an unknown program's interface with the outside world was.
* It does not currently handle hardware interrupts.
* What it does:
*
* 1. Runs the specified program, intercepting certain interrupts
* and recording data in memory.
* 2. Writes an intermediate file filled with Swi_info structures (binary)
* 3. Runs a program called "INTERPRE.EXE" to interpret the
* intermediate file (It's a separate program to keep
* this one small and so you can write your own.)
* It's called like this:
* interpre.exe [-l] infilename outfilename progname [args...]
* where -l denotes long output format.
**************************************************************/
#include <dos.h>
#include <stdio.h>
#include <mem.h>
#include <alloc.h>
#include <process.h>
#include <io.h>
#include <string.h>
#include <dir.h>
#include "intercept.h"
char *usage =
"[-l] [-T tmpdir] [-s maxcalls] [-o outfile] [-d datafile]\n"
"\tprogram [args...]\n"
" -l sets long format output: explanation AND register values\n"
" -T sets temporary directory for intermediate file to \"tmpdir\"\n"
" (will use TMP or TMPDIR environment vars. if found otherwise)\n"
" -s sets the maximum number of SWI records to \"maxcalls\"\n"
" -o names the output filename to \"outfile\" rather than\n"
" the default name (\"intercep.out\")\n"
" -d sets the interrupt data file to use, defaults to INTERPRE.DAT\n"
" program is the name of the program to monitor\n"
" args are any command-line arguments to be passed\n"
" to the monitored program.\n";
char *logo = "INTERCEPT -- monitor DOS and BIOS calls. By:\n"
" Ned Konz\n"
" 210 Oleeta St.\n"
" Ormond Bch, FL 32074\n"
" BIX:nkonz CIS:76046,223 (904)672-2431\n"
" 08/02/1987\n"
" Datafile option and parsing added by Russell Nelson\n";
char switchar, /* DOS parameter switch char (from int 0x21, fn 0x3700) */
sepchar = '\\'; /* DOS filename separator */
void interrupt inthandler ( Regpack r, Intpack i );
int get_swi_list(unsigned);
void install(void);
void uninstall(void);
/* the 8086/8088 INT instruction */
#define SWI_INSTRUCTION 0xCD
/* int_table[] --
* table containg numbers of interrupts we're catching
* and their old handlers
* should be sorted by most common interrupts first.
* NO HARDWARE INTERRUPTS!!!
* Note: some of these may be commented out because they tend to
* quickly fill up the output file. Uncomment and re-compile
* if you want them too.
*/
Intblock
int_table[MAX_INTS + 1]; /* leave room for a terminator */
/* swi_list[] --
* area in memory into which we store data about each SWI
*/
Swi_info huge *swi_list = NULL; /* beginning of swi_list */
Swi_info huge *swi_list_end = NULL; /* just past end of swi_list */
volatile Swi_info huge *swi_next = NULL; /* pointer to next block */
/* our single interrupt handler
* which merely records our registers and interrupt number
* in swi_list[]
* and chains to old handler.
*/
void interrupt
inthandler ( Regpack r, Intpack i )
{
/* the following variables are declared as static to get them
* off the caller's stack and to ensure that t[] is where
* we want it to be: from [BP-01] through [BP-06]
*/
static unsigned char far * caller;
static unsigned char which_int;
static IFP oldhandler;
static Intblock *ibp;
volatile unsigned t[3]; /* to move stack values down by 3 words into */
/* point to next instruction */
caller = (char far *)i.ipcs;
if (caller[-2] != SWI_INSTRUCTION) { /* was this a non-SWI? (uh-oh!) */
uninstall();
exit(-1);
}
which_int = caller[-1]; /* which SWI is this? */
if (FP_SEG(i.ipcs) > _CS && FP_SEG(i.ipcs) < 0xA000
&& swi_next < swi_list_end) {
swi_next->regs = r;
swi_next->caller = i;
swi_next->intnum = which_int;
swi_next++;
}
/* get old handler value */
for (ibp=int_table; ibp->intnum>=0 && ibp->intnum!=which_int; ibp++)
;
if (ibp->intnum < 0) /* can't happen... */
return; /* but if it does, just return "safely" */
oldhandler = ibp->oldint;
/* move all our registers down by 3 words on the stack */
movedata(_SS, FP_OFF(&r), _SS, FP_OFF(t), sizeof(Regpack));
/* supply a mock flag value with interrupts masked OFF */
r.ovl.new.flags = i.flags & ~0x0200;
/* get the address of the routine to chain to */
r.ovl.new.ipcs = oldhandler;
/* bump our frame pointer value down by 3 words --
* the stack pointer will be loaded from this new value next.
*/
_BP -= 6;
/* unstack all registers and do an IRET */
return;
}
int
get_swi_list(unsigned n)
{
if (!(swi_list = farcalloc(n, sizeof(Swi_info))))
return 0;
swi_next = swi_list;
swi_list_end = swi_list + n;
return n;
}
/* install our handler for all the named interrupts
*/
void
install()
{
Intblock *ibp;
IFPP vp;
for (ibp = int_table; ibp->intnum >= 0; ibp++) {
vp = (IFPP) MK_FP(0, ibp->intnum*4);
ibp->oldint = *vp;
disable();
*vp = inthandler;
enable();
}
}
/* un-install our handler for all the named interrupts
*/
void
uninstall()
{
Intblock *ibp;
IFPP vp;
for (ibp = int_table; ibp->intnum >= 0; ibp++) {
if (ibp->oldint != NULL) {
vp = (IFPP) MK_FP(0, ibp->intnum*4);
disable();
*vp = ibp->oldint;
enable();
}
}
}
/* Read template file into buffer, setting pointers to
* beginning of lines.
* Sets template_text, templates and ntemplates.
* Pads out interrupt IDs to 6 characters.
* Returns number of lines.
*/
int
read_template_file(char *filename)
{
FILE *ifile;
char inline[ 100 ];
Intblock *ibp = int_table;
int i;
if (! (ifile = fopen(filename, "rt")))
return 0;
while (fgets(inline, sizeof(inline), ifile)) {
if (ibp - int_table >= MAX_INTS)
return 0;
if (sscanf(inline, "%2x", &i) != 1)
continue;
if (ibp > int_table && i == (ibp-1)->intnum)
continue; /* same as the previous one */
ibp->intnum = i;
ibp->oldint = NULL;
ibp++;
}
ibp->intnum = -1; /* terminate the list */
fclose(ifile);
return 1;
}
/* output structures to intermediate file, call filter program
* return child return code (zero if OK)
*/
int
output_file(char *tmpdir, char *outfilename, int longmode,
char *progname, char *tfilename)
{
Swi_info huge *swip;
Swi_info outrec;
FILE *ofp;
char tempname[ 80 ];
int rval = 0;
sprintf(tempname, "%s%c%s", tmpdir, sepchar, "intercXXXXXX");
if (! mktemp(tempname)) {
fprintf(stderr, "%s: Bad temp file: %s\n", progname, tempname);
return -1;
}
if (! (ofp = fopen(tempname, "wb"))) {
fprintf(stderr, "%s: Can't open intermediate file %s\n",
progname, tempname);
return -1;
}
#ifdef DEBUG
fprintf(stderr, "%s: Using \"%s\" as intermediate file\n",
progname, tempname);
#endif
for (swip = swi_list; swip < (Swi_info huge *)swi_next; swip++) {
outrec = *swip;
if (fwrite(&outrec, sizeof(outrec), 1, ofp) != 1) {
fprintf(stderr, "%s: Write error on file %s\n", progname, tempname);
fclose(ofp);
unlink(tempname);
return -1;
}
}
fclose(ofp);
#ifdef DEBUG
fprintf(stderr, "Running: " OFILTER " %s %s %s %s %s\n",
(longmode ? "-l" : " "), "-t", tfilename, tempname, outfilename
);
#endif
rval = spawnlp(P_WAIT, OFILTER, OFILTER,
(longmode ? "-l" : " "), "-t", tfilename, tempname, outfilename
, NULL);
#ifndef DEBUG
unlink(tempname);
#endif
return rval;
}
void
main(int argc, char *argv[])
{
static unsigned nswi = MAX_INTERRUPTS; /* how many to record? */
static char *ofilename; /* output file name */
static char *tfilename; /* template file name */
static int childret;
static int longmode = 0;
static char tmpdir[ 64 ] = ".";
char *progname;
/* spit out logo */
fprintf(stderr, "%s", logo);
if ((switchar = getswitchar()) != '/')
sepchar = '/';
progname = strrchr(argv[0], sepchar) + 1;
*strchr(progname, '.') = '\0';
/* process cmdline arguments */
if (argc < 2) {
fprintf(stderr, "Usage: %s %s", progname, usage);
exit(1);
}
/* get TMP or TMPDIR (use ofilename as tmp var) */
if ((ofilename = getenv("TMPDIR")) || (ofilename = getenv("TMP")))
strncpy(tmpdir, ofilename, sizeof(tmpdir));
ofilename = OFILENAME;
tfilename = TFILENAME;
while (argv[1][0] == '-') {
char *dummy; /* is this needed? */
switch (argv[1][1]) {
case 's': /* specify max swi calls */
case 'S':
nswi = (unsigned)strtol(argv[2], &dummy, 0);
argv++;
break;
case 'o': /* specify output filename */
case 'O':
ofilename = argv[2];
argv++;
break;
case 'd': /* specify data filename */
case 'D':
tfilename = argv[2];
argv++;
break;
case 'l': /* set long-mode output */
case 'L':
longmode++;
break;
case 't':
case 'T':
strncpy(tmpdir, argv[2], sizeof(tmpdir));
argv++;
break;
default:
fprintf(stderr, "%s: unknown option \"%s\"\n",progname,argv[1]);
fprintf(stderr, "Usage: %s\t%s", progname, usage);
exit(2);
break;
}
argv++;
}
if (! read_template_file( searchpath(tfilename) )) {
fprintf(stderr, "%s: error during read of \"%s\"\n",
progname, tfilename);
exit(5);
}
/* obtain far segment for recording calls */
if (! get_swi_list(nswi)) {
fprintf(stderr, "%s: Can't get enough memory for %u swi records\n",
progname, nswi);
exit(3);
}
else
fprintf(stderr, "%s: Recording up to %u SWI records to file \"%s\"\n",
progname, nswi, ofilename);
/* install our interrupt handler for each interrupt in the list */
install();
/* now run the process */
childret = spawnvp(P_WAIT, argv[1], argv+1);
/* and restore our captured interrupts */
uninstall();
/* report on child return value */
if (childret == -1) {
fprintf(stderr, "%s: Spawn of \"%s\" failed: %s\n",
progname, argv[1], strerror(NULL));
exit(4);
}
if (childret != 0)
fprintf(stderr, "%s: Child process \"%s\" exit value: %d\n",
progname, argv[1], childret);
/* output intermediate file and run output filter program */
if (output_file(tmpdir, ofilename, longmode, progname, tfilename))
fprintf(stderr, "%s: couldn't run output filter program " OFILTER "\n",
progname);
farfree(swi_list);
exit(0);
}